<?php

class S_Model extends CI_Model {
	
	//表名称，不包括数据表前缀
	protected $_table = '';
	
	//表字段数组，字段名为键值的二维数组
	protected $_fields = array();
	
	//结果中记录行数
	protected $_num_rows = 0;
	
	//错误信息
	protected $_error = '';
	
	public function __construct()
	{
		parent::__construct();
		
		if ('S_Model' != get_class($this))
		{
			$this->init();
		}
	}
	
	/*
	 * 数据初始化，表名称，表字段
	 * @access	protected
	 * @return	void
	 */
	protected function init()
	{
		//表名称
		$class = get_class($this);
		if(preg_match('/^(.*)_model$/', $class, $match))
		{
			$this->_table = strtolower($match[1]);
		}
		else
		{
			show_error('模型名称 '.$class.' 错误');
		}
		
		//需不需要缓存字段信息
		$need_cache = FALSE;
		
		//字段信息
		//如果是正式环境了，首先从缓存中取
		if (defined('ENVIRONMENT') && strtolower(ENVIRONMENT) == 'production')
		{
			$need_cache = TRUE;
			$this->load->library('Cache_file', '', 'cache');
			$this->_fields =  $this->cache->get($this->_table.'_fileds_cache');
			if (FALSE !== $this->_fields)
			{
				return;
			}
		}
		
		//数据表字段信息
		$fields = $this->db->field_data($this->_table);
		if ($fields)
		{
			foreach ($fields as $field)
			{
				$this->_fields[$field->name] = (array)$field;
			}
		}
		
		if ($need_cache == TRUE)
		{
			$this->cache->set($this->_table.'_fileds_cache', $this->_fields, 0);
		}
	}
	
	/*
	 * 返回模型表名称
	 * @access	public
	 * @return	string
	 */
	public function table()
	{
		return $this->_table;
	}
	
	/*
	 * 返回模型表字段数组
	 * @access	public
	 * @return	array
	 */
	public function fields()
	{
		return $this->_fields;
	}
	
	/*
	 * 新插入记录的主键值
	 * @access	public
	 * @return	integer
	 */
	public function insert_id()
	{
		return $this->db->insert_id();
	}
	
	/*
	 * 当执行写入操作（insert,update等）的查询后，显示被影响的行数。
	 * @access	public
	 * @return	integer
	 */
	public function affect_rows()
	{
		return $this->db->affect_rows();
	}
	
	/*
	 * 返回查询语句返回记录行数
	 * @access	public
	 * @return	integer
	 */
	public function num_rows()
	{
		return $this->_num_rows;
	}
	
	/*
	 * 最后条执行的语句
	 * @access	public
	 * @return	string
	 */
	public function last_query()
	{
		return $this->db->last_query();
	}
	
	/*
	 * 组建插入语句
	 * @access	public
	 * @param	$data array 数据数组
	 * @return	string
	 */
	public function insert_string($data)
	{
		return $this->db->insert_string($this->_table, $data);	
	}
	
	/*
	 * 组建更新语句
	 * @access	public
	 * @param	$data array 数据数组
	 * @param	$condition array 条件数组
	 * @return	string
	 */
	public function update_string($data, $condition = NULL)
	{
		return $this->db->update_string($this->_table, $data, $condition);
	}

	/*
	 * 统计，若不存在条件，直接统计这个表
	 * @access	public
	 * @param	$condition array 条件数组
	 * @return	integer
	 */
	public function get_count($condition = NULL)
	{
		if ( ! $condition)
		{
			return $this->db->count_all($this->_table);
		}
		
		$condition = $this->parse_condition($condition);
		
		$this->db->select('count(*) as count');
		$this->db->from($this->_table);
		$this->db->where($condition);
		$query = $this->db->get();
		$result = $query->row_array();
		$query->free_result();
		return intval($result['count']);
	}
	
	/*
	 * 根据条件判断是否存在，存在返回TRUE，失败返回FALSE
	 * @access	public
	 * @param	$condition array|integer 条件数组
	 * @return	boolean
	 */
	public function exists($condition)
	{
		$condition = $this->parse_condition($condition, TRUE);
		$this->db->select('id');
		$this->db->from($this->_table);
		$this->db->where($condition);
		$this->db->limit(1);
		$query = $this->db->get();
		$result = $query->row_array();
		$query->free_result();
		return (boolean)$result;
	}
	
	/*
	 * 根据主键返回记录
	 * @access	public
	 * @param	$id integer 主键值
	 * @param	$fields string|array 要返回的字段，字符串或数组，字符串格式：'name,username,password',数组格式：array('name', 'username', 'password')
	 * @return	array
	 */
	public function get($id, $fields = '')
	{
		$fields = $this->parse_fields($fields);
		
		$condition = array(
			'id' => intval($id)
		);
		
		$this->db->select($fields);
		$this->db->from($this->_table);
		$this->db->where($condition);
		$this->db->limit(1);
		$query = $this->db->get();
		$this->_num_rows = $query->num_rows();
		$result = $query->row_array();
		$query->free_result();
		return $result;
	}
	
	/*
	 * 根据条件查询一条记录的某个字段信息，不存在返回FALSE
	 * @access	public
	 * @param	$name string 字段名称
	 * @param	$condition array 条件数组
	 * @return	mixed
	 */
	public function get_field($name, $condition = NULL)
	{
		$condition = $this->parse_condition($condition, TRUE);

		$this->db->select($name);
		$this->db->from($this->_table);
		
		if ($condition)
		{
			$this->db->where($condition);
		}
		
		$this->db->limit(1);
		
		$query = $this->db->get();
		$this->_num_rows = $query->num_rows();
		$result = $query->row_array();
		$query->free_result();
		return current($result);
	}

	/*
	 * 根据条件返回一条数据
	 * @access	public
	 * @param	$condition array 条件
	 * @param	$fields string|array 要返回的字段，字符串或数组，字符串格式：'name,username,password',数组格式：array('name', 'username', 'password')
	 * @return	array
	 */
	public function get_one($condition = NULL, $fields = '')
	{
		$condition = $this->parse_condition($condition, TRUE);
		$fields = $this->parse_fields($fields);
		$this->db->select($fields);
		$this->db->from($this->_table);
		$this->db->where($condition);
		$this->db->limit(1);
		$query = $this->db->get();
		$this->_num_rows = $query->num_rows();
		$result = $query->row_array();
		$query->free_result();
		return $result;
	}
	
	//同上
	public function get_row($condition = NULL, $fields = '')
	{
		return $this->get_one($condition, $fields);
	}
	
	/*
	 * 返回多条记录
	 * @access	public
	 * @param	$condition array 条件
	 * @param	$fields string|array 要返回的字段，字符串或数组，字符串格式：'name,username,password',数组格式：array('name', 'username', 'password')
	 * @param	$order string 排序,默认主键升序
	 * @param	$start integer 从哪行开始
	 * @param	$limit integer 返回条数
	 * @return	array
	 */
	public function get_list($condition = NULL, $fields = '', $order = 'id ASC', $start = 0, $limit = 10)
	{
		$condition = $this->parse_condition($condition);
		$fields = $this->parse_fields($fields);
		$this->db->select($fields);
		$this->db->from($this->_table);
		$this->db->where($condition);
		$this->db->order_by($order);
		$this->db->limit($limit, $start);
		$query = $this->db->get();
		$this->_num_rows = $query->num_rows();
		$result = $query->result_array();
		$query->free_result();
		return $result;
	}
	
	/*
	 * 返回多条记录
	 * @access	public
	 * @param	$condition array 条件
	 * @param	$fields string|array 要返回的字段，字符串或数组，字符串格式：'name,username,password',数组格式：array('name', 'username', 'password')
	 * @param	$order string 排序,默认主键升序
	 * @return	array
	 */
	public function get_all($condition = NULL, $fields = '', $order = 'id ASC')
	{
		$condition = $this->parse_condition($condition);
		$fields = $this->parse_fields($fields);
		$this->db->select($fields);
		$this->db->from($this->_table);
		$this->db->where($condition);
		$this->db->order_by($order);
		$query = $this->db->get();
		$this->_num_rows = $query->num_rows();
		$result = $query->result_array();
		$query->free_result();
		return $result;
	}
	
	/*
	 * 返回分页数据
	 * @access	public
	 * @param	$p integer 页码
	 * @param	$per_page integer 每页显示多少数据，默认10
	 * @param	$conditon array 条件
	 * @param	$fields string|array 要返回的字段，字符串或数组，字符串格式：'name,username,password',数组格式：array('name', 'username', 'password')
	 * @param	$order string 排序,默认主键降序
	 * @return	array
	 */
	public function get_page($p = 1, $per_page = 10, $condition = NULL, $fields = '', $order = 'id DESC')
	{
		return $this->get_list($condition, $fields, $order, ($p-1)*$per_page, $per_page);
	}
	
	/*
	 * insert into方式插入数据,失败返回FALSE，成功返回插入的id
	 * @access	public
	 * @param	$data array 数据数组
	 * @return	mixed
	 */
	public function insert($data)
	{		
		if (FALSE === $this->db->insert($this->_table, $data))
		{
			return FALSE;
		}

		return $this->db->insert_id();
	}
	
	/*
	 * replace into方式插入数据,失败返回FALSE，成功返回插入的id
	 * @access	public
	 * @param	$data array 数据数组
	 * @return	mixed
	 */
	public function replace($data)
	{		
		if (FALSE === $this->db->replace($this->_table, $data))
		{
			return FALSE;
		}

		return $this->db->insert_id();
	}
	
	/*
	 * 修改数据,成功返回修改的记录数，失败返回FALSE
	 * @access	public
	 * @param	$data array 数据数组
	 * @param	$condition array 条件
	 * @return	integer
	 */
	public function update($data, $condition)
	{
		$condition = $this->parse_condition($condition, TRUE);
		
		if (FALSE === $this->db->update($this->_table, $data, $condition))
		{
			return FALSE;
		}
		
		return $this->db->affected_rows();
	}
	
	/*
	 * 根据条件删除记录,失败返回FALSE，成功返回删除的记录条数 例如：delete(1)或者delete(数组形式的where条件)
	 * @access	public
	 * @param	$condition array 条件
	 * @return	integer
	 */
	public function delete($condition)
	{	
		$condition = $this->parse_condition($condition, TRUE);
		
		if (FALSE === $this->db->delete($this->_table, $condition))
		{
			return FALSE;
		}
		
		return $this->db->affected_rows();
	}
	
	/*
	 * 解析要查询的字段，返回字符串格式的查询字段，如"id,name,value"
	 * @access	public
	 * @param	$field string|array
	 * @return	string
	 */
	public function parse_fields($fields)
	{
		if ($fields == '' || $fields == '*')
		{
			$fields = array_keys($this->_fields);
		}
		
		if (is_array($fields))
		{
			return implode(',', $fields);
		}
		
		return trim($fields);
	}
	
	/*
	 * 解析查询条件,返回数组或字符串格式的查询语句
	 * @access	public
	 * @param	$condition array 条件
	 * @param	$use_id boolean 是否解析主键id
	 * @return	array
	 */
	public function parse_condition($condition, $use_id = FALSE)
	{
		if ( ! $condition)
		{
			return array();
		}
		
		if (is_array($condition))
		{
			return $condition;
		}

		elseif ($use_id && is_numeric($condition))
		{
			return array(
				'id' => intval($condition)
			);
		}
		
		return trim($condition);
	}
	
	/*
	 * 设置错误信息
	 * @access	public
	 * $param	$error string 错误信息
	 * @return	void
	 */
	public function set_error($error)
	{
		$this->_error = $error;
	}
	
	/*
	 * 返回错误信息
	 * @access	public
	 * @return	string
	 */
	public function get_error()
	{
		return $this->_error;
	}
	
}